package logic

import (
	"context"
	"fmt"
	"github.com/go-redsync/redsync/v4"
	"github.com/go-redsync/redsync/v4/redis/goredis/v9"
	goredislib "github.com/redis/go-redis/v9"
	uuid "github.com/satori/go.uuid"
	"github.com/zeromicro/go-zero/core/logx"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"gorm.io/gorm"
	"order_srv/appconfig"
	"order_srv/internal/model"
	"order_srv/internal/svc"
	"order_srv/order_proto"
)

type CreateOrderLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewCreateOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateOrderLogic {
	return &CreateOrderLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *CreateOrderLogic) CreateOrder(in *order_proto.CreateOrderRequest) (*order_proto.OrderInfo, error) {
	// todo: add your logic here and delete this line
	client := goredislib.NewClient(&goredislib.Options{
		Addr: fmt.Sprintf("%s:%d", appconfig.AppConf.RedisConfig.Host, appconfig.AppConf.RedisConfig.Port),
	})
	pool := goredis.NewPool(client)
	rs := redsync.New(pool)
	mutexName := "order-mutex"
	mutex := rs.NewMutex(mutexName)
	if err := mutex.LockContext(context.Background()); err != nil {
		zap.S().Info("开启redis分布式事务失败")
		return nil, status.Errorf(codes.Internal, "开启redis分布式事务失败")
	}
	tx := model.DB.Begin()
	var goods model.Goods
	find := tx.Where(&model.Goods{Model: gorm.Model{ID: uint(in.GoodsId)}}).Find(&goods)
	if find.RowsAffected == 0 {
		tx.Rollback()
		zap.S().Info("商品不存在")
		return nil, status.Errorf(codes.NotFound, "商品不存在")
	}

	if in.Stock > goods.Stock {
		zap.S().Info("库存不足")
		return nil, status.Errorf(codes.Internal, "库存不足")
	}
	price := goods.Price * float32(in.Stock)
	orderSn := fmt.Sprintf("%s", uuid.NewV4())
	order := model.Order{
		UserId:  in.UserId,
		GoodsId: in.GoodsId,
		Price:   price,
		OrderSn: orderSn,
		Num:     in.Stock,
	}
	save := tx.Save(&order)
	if save.Error != nil {
		tx.Rollback()
		zap.S().Info("创建订单失败")
		return nil, status.Errorf(codes.Internal, "创建订单失败")
	}
	goods.Stock -= in.Stock
	update := tx.Save(&goods)
	//stock := goods.Stock - in.Stock
	//update := tx.Where(&model.Goods{Model: gorm.Model{ID: uint(in.GoodsId)}}).Update("stock", stock)
	if update.Error != nil {
		tx.Rollback()
		zap.S().Info("扣减库存失败")
		return nil, status.Errorf(codes.Internal, "扣减库存失败")
	}
	tx.Commit()
	if ok, err := mutex.UnlockContext(context.Background()); !ok || err != nil {
		zap.S().Info("释放redis分布式事务失败")
		return nil, status.Errorf(codes.Internal, "释放redis分布式事务失败")
	}
	return &order_proto.OrderInfo{
		Id:      int32(order.ID),
		UserId:  order.UserId,
		GoodsId: order.GoodsId,
		Price:   order.Price,
		PayType: order.PayType,
		Status:  order.Status,
		OrderSn: order.OrderSn,
		TradeNo: order.TradeNo,
		Num:     order.Num,
	}, nil
}
